package netty.client;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
public class UpTimeClientHandler extends SimpleChannelInboundHandler<Object> {

    private final UpTimeClient upTimeClient;

    public UpTimeClientHandler(UpTimeClient upTimeClient) {
        this.upTimeClient = upTimeClient;
        log.info(">>> init {}", this.toString());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // super.userEventTriggered(ctx, evt);
        log.info("evt: {}", evt);

        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent)evt;
            if (!event.isFirst()) {
                log.info("Disconnecting due to no inbound traffic. {}", this);
                ctx.channel().close();
            }
        }
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        log.info("Sleeping for: " + UpTimeClient.RECONNECT_DELAY + 's');
        ctx.channel().eventLoop().schedule(() -> {
            upTimeClient.connect();
        }, UpTimeClient.RECONNECT_DELAY, TimeUnit.SECONDS);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.executor().schedule(() -> {
            ctx.writeAndFlush(Unpooled.wrappedBuffer("ping".getBytes()));
        }, 3, TimeUnit.SECONDS);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        log.info("Disconnecting from {}. {}", ctx.channel().remoteAddress(), this);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        // Server is supposed to send nothing, but if it sends something, discard it.
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Close the connection when an exception is raised.
        cause.printStackTrace();
        ctx.close();
    }
}
